﻿using System;
using System.Windows.Forms; // So we can show a messagebox.
using System.Drawing;
using System.Threading; // To slow the preview mode to normal speed.
using System.IO;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
using System.Collections.Generic;

using mKoenig.PictureSlide.Properties;

namespace mKoenig.PictureSlide
{
  public class Minipreview
  {
    private int maxFiles = 200;
    private Settings setting = Settings.Default;

    private DateTime startTime;

    private int mode = 10;
    private int pic = 1;
    private Render.ImageData img;

    public void DoMiniPreview(int argHandle)
    {
      GetPictures();
      
      // Pointer to windows Display Properties window.
      IntPtr ParentWindowHandle = new IntPtr(0);
      ParentWindowHandle = (IntPtr)argHandle; // Get the pointer to Windows Display Properties dialog. 
      RECT rect = new RECT();
      // The Using construct is to make sure all resources used here are cleared in case of unhandled exceptions.
      using (Graphics PreviewGraphic = Graphics.FromHwnd(ParentWindowHandle)) // This is the mini-preview window from the OS. 
      {
        DateTime dt30Seconds = DateTime.Now.AddSeconds(30);

        GetClientRectApi(ParentWindowHandle, ref rect); // Get the dimensions and location of the preview window.
        { 
          // create a local scope to ensure that dt30SEconds goes out of scope as soon as unneeded.
          // The parent window is never ready when preview is chosen, before we try to get the visible state. 
          // So we must wait. I limit my waiting to 30 seconds. 
          while (IsWindowVisibleApi(ParentWindowHandle) == false)
          {
            if (DateTime.Now > dt30Seconds) return; // If time runs out, exit program.
            Application.DoEvents(); // We don't want to ignore windows, or we might be sorry! :) Respond to events.
          }
        } // After this point the dt30Seconds goes away.

        int x = rect.right - rect.left;
        int y = rect.bottom - rect.top;

        LoadPicture(new Size(x,y));

        Render render = new Render(new Size(x, y));
        Render.ImageData data = new Render.ImageData();

        startTime = DateTime.Now;

        while (IsWindowVisibleApi(ParentWindowHandle) == true) // Now that the window is visible ...
        {
          data.Image = img.Image;
          data.Name = string.Empty;
          data.Date = string.Empty; ;
          data.Info = string.Empty;

          TimeSpan span = DateTime.Now - startTime;
          double ms = span.TotalMilliseconds;
          render.DoRender((Render.slideShowTransistionFrames / 2000.0f * (float)ms), (int)mode, PreviewGraphic, data, true);

          if (ms > 3500)
          {
            LoadPicture(new Size(x,y));
          }
          Application.DoEvents();
        }
      }
    }

    private void GetPictures()
    {
      bool stop = false;

      Console.WriteLine(DateTime.Now.ToLongTimeString() + ": Start scan directory");

      string[] rootfiles = Directory.GetFiles(setting.PicturePath, "*.jpg", SearchOption.TopDirectoryOnly);
      foreach (string aFile in rootfiles)
      {
        FileHandling handler = FileHandling.GetInstance();
        if (handler.Count <= maxFiles)
          handler.Add(aFile);
        else
        {
          stop = true;
          break;
        }
      }
      if (!stop)
        DirSearch(setting.PicturePath);
    }
    private void DirSearch(string sDir)
    {
      FileHandling handler = FileHandling.GetInstance();

      bool stop = false;

      string[] dirs = Directory.GetDirectories(sDir);

      foreach (string d in dirs)
      {
        string[] files = Directory.GetFiles(d, "*.jpg");
        foreach (string f in files)
        {
          if (handler.Count < maxFiles)
            handler.Add(f);
          else
          {
            stop = true;
            break;
          }
        }
        if (!stop)
          DirSearch(d);
      }
    }

    private void LoadPicture(Size size)
    {
      FileHandling handler = FileHandling.GetInstance();
      mode = TransitionEnabler.NextTransition();
      //mode = 26;

      pic = new Random().Next(handler.Count);
      img = handler.LoadImage(pic, new Size(size.Width, size.Height));

      startTime = DateTime.Now;
    }

    public struct RECT
    {
      public int left;
      public int top;
      public int right;
      public int bottom;

      public RECT(int l, int t, int r, int b)
      {
        left = l;
        top = t;
        right = r;
        bottom = b;
      }
    }

    /// Declares an API call to determine if a window is visible.
    /// /summary>
    /// param name="hWnd"> Handle to the window being checked for visibility.</param>
    /// returns> Returns true if the window is visible, false if not.</returns>
    [DllImport("user32.DLL", EntryPoint = "IsWindowVisible")]
    private static extern bool IsWindowVisible(IntPtr hWnd);

    /// <summary>
    /// Declare an external API function call. A wrapper function calls this.
    /// </summary>
    /// <param name="hWnd"> Handle to the window being addressed.</param>
    /// <param name="rect"> Struct containing Size and Location to be filled with the client area size and loc.</param>
    /// <returns> true is success, otherwise false.</returns>
    [DllImport("user32.dll")]
    private static extern bool GetClientRect(IntPtr hWnd, ref RECT rect);

    /// <summary>
    /// Wrapper to call the IsWindowVisible api call.
    /// </summary>
    /// <param name="hWnd">Handle to the Desktop Properties window.</param>
    /// <returns></returns>
    public bool IsWindowVisibleApi(IntPtr hWnd)
    {
      return IsWindowVisible(hWnd);
    }
    /// <summary>
    /// Wrapper to call GetClientRect API functions in user32.dll to get size of the client area of a window.
    /// </summary>
    /// <param name="hWnd"> This is a handle to the desktop properties dialog box</param>
    /// <param name="rect"> This is an instance of a RECT struct to be filled with the location & size of the client area.
    /// </param>
    /// <returns>true if successful, false if uncuccessful</returns>
    public bool GetClientRectApi(IntPtr hWnd, ref RECT rect)
    {
      return GetClientRect(hWnd, ref rect);
    }



  

  }
}
